package com.xmh.reptile.main;

import com.gargoylesoftware.htmlunit.*;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.javascript.DefaultJavaScriptErrorListener;
import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener;
import com.gargoylesoftware.htmlunit.javascript.host.Window;
import com.xmh.reptile.ReptileApplication;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

@RunWith(SpringRunner.class)
@Component
@SpringBootTest(classes = ReptileApplication.class)
@Slf4j
public class JinRiTouTiaoReptile {

    final WebClient webClient = new WebClient(BrowserVersion.CHROME);// 新建一个模拟谷歌Chrome浏览器的浏览器客户端对象

    @Test
    public void main() throws IOException, InterruptedException {
        String cssQuery = "title";
        String url = "https://www.toutiao.com/i6829492913005658631/?tt_from=android_share&utm_campaign=client_share&app=news_article%C3%97tamp%3D1590128198&utm_medium=toutiao_android&use_new_style=0&req_id=202005221416380100160172041C217CB9&group_id=6829492913005658631";
//        String url = "https://www.baidu.com/?id=100";
//        String cssQuery = "#s-hotsearch-wrapper > div > a.hot-title > div";

        String htmlData = getHtmlData(cssQuery, url);

        System.out.println(htmlData);
    }

    private String getHtmlData(String cssQuery, String url) throws IOException {
        webClient.getOptions().setThrowExceptionOnScriptError(false);// 当JS执行出错的时候是否抛出异常, 这里选择不需要
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);// 当HTTP的状态非200时是否抛出异常, 这里选择不需要
        webClient.getOptions().setCssEnabled(false);// 是否启用CSS, 因为不需要展现页面, 所以不需要启用
        webClient.getOptions().setJavaScriptEnabled(true); // 很重要，启用JS
        webClient.setJavaScriptEngine(new MyJavaScriptEngine(webClient));// 自定义JavaScript引擎，有js错误不打印
        webClient.setAjaxController(new NicelyResynchronizingAjaxController());// 很重要，设置支持AJAX

//        webClient.getOptions().setTimeout(5000);
        webClient.setJavaScriptErrorListener(new MyJSErrorListener());
//        webClient.setJavaScriptTimeout(5000);


        HtmlPage page = webClient.getPage(url.trim());

        page.remove();

        webClient.waitForBackgroundJavaScript(1000);// 异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束

        String html = page.asXml();

        return Jsoup.parse(html).select(cssQuery).text();
    }


    public class MyJSErrorListener extends DefaultJavaScriptErrorListener {
        @Override
        public void scriptException(HtmlPage page, ScriptException scriptException) {
        }

        @Override
        public void timeoutError(HtmlPage page, long allowedTime, long executionTime) {
        }

        @Override
        public void malformedScriptURL(HtmlPage page, String url, MalformedURLException malformedURLException) {

        }

        @Override
        public void loadScriptError(HtmlPage page, URL scriptUrl, Exception exception) {

        }

        @Override
        public void warn(String message, String sourceName, int line, String lineSource, int lineOffset) {

        }
    }

    public class MyJavaScriptEngine extends JavaScriptEngine {

        public MyJavaScriptEngine(WebClient webClient) {
            super(webClient);
        }

        @Override
        protected void handleJavaScriptException(final ScriptException scriptException, final boolean triggerOnError) {
            // Trigger window.onerror, if it has been set.
            HtmlPage page = scriptException.getPage();
            if (triggerOnError && page != null) {
                final WebWindow window = page.getEnclosingWindow();
                if (window != null) {
                    final Window w = (Window) window.getScriptableObject();
                    if (w != null) {
                        try {
                            w.triggerOnError(scriptException);
                        } catch (final Exception e) {
                            handleJavaScriptException(new ScriptException(page, e, null), false);
                        }
                    }
                }
            }
/*            final JavaScriptErrorListener javaScriptErrorListener = getWebClient().getJavaScriptErrorListener();
            if (javaScriptErrorListener != null) {
                javaScriptErrorListener.scriptException(page, scriptException);
            }
            // Throw a Java exception if the user wants us to.
            if (getWebClient().getOptions().isThrowExceptionOnScriptError()) {
                throw scriptException;
            }
            // Log the error; ScriptException instances provide good debug info.
            // LOG.info("Caught script exception", scriptException);*/
        }

    }

}
